#define LOG_NDEBUG 0
#define LOG_TAG "AudioNetIPCP"

#include "ap/AudioNetIPCP.h"

#include <ipcp/ipcp.h>
#include <ipcp/packet.h>
#include <log/log.h>
#include <transfer/SafeQueue.h>
#include <transfer/SignalStorage.h>
#include <transfer/utils.h>
#include "McuControlWrapper.h"
#include "common.h"
#include "convertFromIPCPValue.h"
#include <vendor/ecarx/xma/automotive/vehicle/2.0/types.h>

using namespace ::vendor::ecarx::xma::automotive::vehicle::V2_0;

namespace ecarx::transfer::ipcp{
static utils::ConcurrentQueue<ecarx::transfer::ipcp::IpcpValue> mIpcpQueue;
static utils::BatchingConsumer<ecarx::transfer::ipcp::IpcpValue> mBatchingConsumer;

class AudioIPCPConn::AudioNetIPCP{
    public:
        AudioNetIPCP(){
            mState = NetState::INIT;
            mBatchingConsumer.run(&mIpcpQueue,
                            std::bind(&AudioNetIPCP::readThread, this, std::placeholders::_1));

            mMcuControl = McuControl::getInstance();
            mMcuControl->setAudioReceivedCallback(audioReceviedCallback);
        }

        ~AudioNetIPCP(){
            ALOGD("audio ipcp release");
            mBatchingConsumer.requestStop();
            mIpcpQueue.deactivate();
            mBatchingConsumer.waitStopped();

            close();
        }

        //打开 IPCP 连接
        bool open(){
            ALOGD("dbgstart audio ipcp open");
            bool openState = false;
            notifyNetState(NetState::Open);
            int error_code = STACK_START_SUCCESS;
            error_code = mMcuControl->setupConnection(AUDIO_SERVICEID_SECOND);
            openState = error_code == STACK_START_SUCCESS;
            ALOGD("dbgstart audio ipcp ready");
            notifyNetState(NetState::Ready);
            return openState;
        }

        //restore MCU Audio Settings Data
        // template <typename _TY>
        void restoreAudioSettings(int32_t propertyId,int32_t value){
            ALOGD("funtion: [%s],restoreAudioSettings====propertyId:%d", __FUNCTION__,propertyId);
            switch (propertyId){
                case  static_cast<int32_t>(ECarXVehicleProperty::SETTING_FUNC_SOUND_WARNING_VOLUME):
                    getMcuControl()->setWarnVolLevl(static_cast<int32_t>(value));
                    break;
                case static_cast<int32_t>(ECarXVehicleProperty::SETTING_FUNC_AUDIO_SEAT_SOUND_OPTIMIZE):
                    getMcuControl()->setSeatOptimization(value);
                    break;
                case static_cast<int32_t>(ECarXVehicleProperty::SETTING_FUNC_AUDIO_COMPENSATION_LEVEL):
                    getMcuControl()->setVehicleSpeedLevel(value);
                    break;
                case static_cast<int32_t>(ECarXVehicleProperty::SETTING_FUNC_AUDIO_2D_SURROUND_SHOUND_EFFECT_LEVEL):
                    getMcuControl()->setTwoSurroundLvl(value);
                    break;
                default:
                    break;
            }
        }

        //关闭 IPCP 连接
        bool close(){
            ALOGD("audio ipcp close");
            notifyNetState(NetState::Close);
            ipcp_cleanup();
            return true;
        }

        //数据写入 IPCP 协议栈并向MCU发送
        bool write(const Signal& signal){
            return false;
        }

        //接收 libaudiomcucontrol 回调的 IPCP 消息
        static void audioReceviedCallback(ipcp_packet_t* packet, ipcp_peer_t peer){
            ALOGD("funtion: [%s],audio ipcp received callback", __FUNCTION__);
            std::size_t payload_len = packet->header.length - PACKET_HEADER_OFFSET;
            if (payload_len > 0) {
                    ecarx::transfer::ipcp::IpcpValue value;
            value.service_id = packet->header.service_id;
            value.oper_id = packet->header.operation_id;
            value.oper_type = packet->header.op_type;
            value.payload_type = packet->header.payload_type;
            // service ip
            memset(value.peer_ip, 0, sizeof(value.peer_ip));
            strcpy(value.peer_ip, peer.peer_ip);
            // service port
            value.peer_port = peer.peer_port;
            // payload
            value.payload_len = payload_len;
            value.payload = (void*)new uint8_t[value.payload_len];
            memcpy(value.payload, packet->payload, value.payload_len);
            ALOGD("funtion: [%s], service id %d opid %d ", __FUNCTION__, packet->header.service_id,
                  packet->header.operation_id);
            mIpcpQueue.push(std::move(value));
            }

        }

        void readThread(const ecarx::transfer::ipcp::IpcpValue& value) {
            std::vector<int32_t> changed;
            std::vector<ecarx::transfer::Signal> buffer = ecarx::transfer::utils::ipcpDataToSignals(value);
            mAPVPStorage.put(buffer,changed);
            ALOGE("funtion: [%s] ,audio ipcp info : service_id=[%d],opId=[%d],opType[%d],payLoadLen=[%ld]",
                   __FUNCTION__,value.service_id, value.oper_id, value.oper_type, value.payload_len);

            ALOGD("funtion: [%s],changed%d", __FUNCTION__,changed.size());
            if (!changed.empty()) {
                mSignalChangeCallback(changed);
            }
            delete[](uint8_t*) value.payload;            
        }

        const std::optional<Signal> read(const int32_t signalId){
            return mAPVPStorage.get(signalId);
        }

        NetState getState(){
            return mState;
        }

        void onSignalChanged(SignalChangeCallback&& callback){
            ALOGD("funtion: [%s] ====",__FUNCTION__);
            mSignalChangeCallback = callback;
        }

        void registerStateHandler(NetStateCallback&& callback){
            mStateCallback = callback;
        }

        void notifyNetState(NetState state){
            mState = state;
            if(mStateCallback != nullptr){
                mStateCallback(state);
            }

        }

        McuControl* getMcuControl(){
            return mMcuControl;
        }

    private:
        McuControl* mMcuControl = NULL;
        NetState mState;
        storage::SignalPool mAPVPStorage;
        NetStateCallback mStateCallback;
        SignalChangeCallback mSignalChangeCallback;
};


AudioIPCPConn::AudioIPCPConn():mImpl(new AudioNetIPCP()){}

AudioIPCPConn::~AudioIPCPConn(){
    delete mImpl;
}

bool AudioIPCPConn::open(){
    return mImpl->open();
}

bool AudioIPCPConn::close(){
    return mImpl->close();
}

bool AudioIPCPConn::write(const Signal& signal){
    return mImpl->write(signal);
}

const std::optional<Signal> AudioIPCPConn::read(const int32_t signal) const{
    return mImpl->read(signal);
}

NetState AudioIPCPConn::getState(){
    return mImpl->getState();
}

void AudioIPCPConn::onSignalChanged(SignalChangeCallback&& callback){
    mImpl->onSignalChanged(std::move(callback));
}

void AudioIPCPConn::registerStateHandler(NetStateCallback&& callback){
    mImpl->registerStateHandler(std::move(callback));
}

McuControl* AudioIPCPConn::getMcuControl() { 
    return mImpl->getMcuControl();
}

// template <typename _TY>
void AudioIPCPConn::restoreAudioSettings(int32_t propertyId,int32_t value){
    mImpl->restoreAudioSettings(propertyId,value);
}
}
